package org.elephas.webapp.application;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.jcr.Credentials;
import javax.jcr.Repository;
import javax.jcr.SimpleCredentials;

import org.apache.jackrabbit.core.RepositoryImpl;
import org.apache.jackrabbit.core.config.RepositoryConfig;
import org.apache.wicket.Application;
import org.apache.wicket.IConverterLocator;
import org.apache.wicket.Request;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.Response;
import org.apache.wicket.Session;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.protocol.http.WebResponse;
import org.apache.wicket.request.target.coding.HybridUrlCodingStrategy;
import org.apache.wicket.request.target.coding.IndexedParamUrlCodingStrategy;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import org.apache.wicket.util.convert.ConverterLocator;
import org.apache.wicket.util.convert.IConverter;
import org.elephas.model.ElephasConfiguration;
import org.elephas.model.User;
import org.elephas.webapp.application.security.ElephasAuthorizationStrategy;
import org.elephas.webapp.backend.page.BaseAdminPage;
import org.elephas.webapp.converters.UserConverter;
import org.elephas.webapp.frontend.page.FrontPage;
import org.elephas.webapp.frontend.page.RegisterPage;
import org.elephas.webapp.frontend.page.blog.BlogFrontPage;
import org.elephas.webapp.frontend.page.blog.BlogPostPage;
import org.elephas.webapp.model.DetachableElephasConfigurationModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Application object for your web application. If you want to run this
 * application without deploying, run the Start class.
 * 
 * @see wicket.myproject.Start#main(String[])
 */
public class ElephasApplication extends WebApplication {

	private static final Logger log = LoggerFactory
			.getLogger(ElephasApplication.class);

	private DetachableElephasConfigurationModel config;
	private AppProperties props;
	private Repository repository;

	/**
	 * @see Application#getHomePage()
	 */
	@Override
	public Class<? extends WebPage> getHomePage() {
		return FrontPage.class;
	}

	/**
	 * @see WebApplication#init()
	 */
	@Override
	protected void init() {
		try {
			props = new AppProperties();
		} catch (IOException e) {
			throw new RuntimeException("Could not load application properties",
					e);
		}
		addComponentInstantiationListener(new SpringComponentInjector(this));

		getSecuritySettings().setAuthorizationStrategy(
				new ElephasAuthorizationStrategy());

		mountBookmarkablePage("recent", FrontPage.class);
		mountBookmarkablePage("register", RegisterPage.class);
		mount(new IndexedParamUrlCodingStrategy("/blog", BlogFrontPage.class));
		mount(new IndexedParamUrlCodingStrategy("/post", BlogPostPage.class));

		mount(new HybridUrlCodingStrategy("admin", BaseAdminPage.class));

		initRepository();
	}

	private void initRepository() {
		try {
			File home = new File(props.getJcrRepositoryLocation());
			InputStream configStream = new FileInputStream(new File(home,
					"repository.xml"));
			RepositoryConfig config = RepositoryConfig.create(configStream,
					home.toString());
			configStream.close();
			repository = RepositoryImpl.create(config);

			Credentials cred = new SimpleCredentials(getProps().getJcrLogin(),
					getProps().getJcrPassword().toString().toCharArray());
			javax.jcr.Session session = repository.login(cred);

		} catch (Exception e) {
			log.error("Couldn't init jackrabbit repository, make sure you"
					+ " have the jcr.repository.location config property set",
					e);
		}
	}

	public AppProperties getProps() {
		return props;
	}

	protected IConverterLocator newConverterLocator() {
		return new ElephasConverterLocator();
	}

	/**
	 * @see WebApplication#newSession(Request, Response)
	 */
	@Override
	public Session newSession(Request request, Response response) {
		return new ElephasSession(request);
	}

	@Override
	public RequestCycle newRequestCycle(Request request, Response response) {
		return new ElephasRequestCycle(this, (WebRequest) request,
				(WebResponse) response);
	}

	/**
	 * Loads the blog application configuration object.
	 * 
	 * @return the blog application configuration
	 */
	public synchronized ElephasConfiguration getElephasConfiguration() {
		if (config == null) {
			config = new DetachableElephasConfigurationModel();
		}
		return config.getObject();
	}

	public static ElephasApplication get() {
		return (ElephasApplication) Application.get();
	}

	private static class ElephasConverterLocator implements IConverterLocator {
		public IConverter getConverter(Class aClass) {
			IConverter converter = null;
			if (aClass.equals(User.class)) {
				converter = new UserConverter();
			} else {
				converter = new ConverterLocator().getConverter(aClass);
			}
			return converter;
		}
	}
}
